// loadsh.debounce 的算法实现，为了更好的理解，对原代码做了一些简化
export default function (func, wait, immediate) {
  var timeout, args, context, timestamp, result
  if (null == wait) wait = 100

  function later() {
    // last 等于当前时间差动最近一次时间戳
    // 也就是 Date.now() - 10ms
    var last = Date.now() - timestamp
    if (last < wait && last >= 0) {
      // 重新设定延时执行时间 wait - last
      // 假设wait:100ms，那么100 - 90 = 10ms
      // 那么再延后10ms 就是从最近一次触发，到fun 的执行，刚好是 wait这个时间间隔
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      if (!immediate) {
        result = func.apply(context, args)
        context = args = null
      }
    }
  }

  var debounced = function () {
    // 缓存最近一次触发的执行上下文
    context = this
    // 缓存最近一次触发的函数参数
    args = arguments
    // 记录最近一次触发的时间戳
    timestamp = Date.now()
    // 是否立即执行,不用理会
    var callNow = immediate && !timeout
    // 为了更加具体化，我们来模拟2次用户的操作
    // 分别是：0ms操作一次，10ms 操作一次
    // ----- 执行过程如下 -----
    // 0ms的操作，timeout 是 undifined，取反为真值，则执行 setTimeout(later, wait);
    // 10ms的操作，timeout 为上面那一步的 定时器id值，取反为假值，保存了上下文，参数，不做其它的处理
    // 这个设计非常巧妙，成功避开高频操作clearTimeout,带来的损耗
    // 聊了一会天，时间到了wait 的设定值，执行later（此时不考虑堵塞什么的）
    // 此时，我们看看later 函数的内部细节
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
  return debounced
}
